﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Globalization;
using System.Windows.Forms;

using cit.CopyDetection.DataObject;
using cit.CopyDetection.Model;

namespace cit.CopyDetection
{
    public partial class frmCopyDetection : Form
    {
        private bool discreteValue = false;
        private List<string> files;
        private BackgroundWorker bWorker;
        private Dictionary<string, Dictionary<Document, double>> displayItems;
        private Dictionary<string, string> verifiedDocuments;
        private VectorSpace vectorSpace;

        public frmCopyDetection()
        {
            InitializeComponent();

            files = new List<string>();
            verifiedDocuments = new Dictionary<string, string>();

            bWorker = new BackgroundWorker();
            bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);
            bWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bWorker_RunWorkerCompleted);
        }

        private void bWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (vectorSpace == null)
                vectorSpace = new VectorSpace();

            if (discreteValue)
                vectorSpace.SemanticDimension = (int)nudValue.Value;
            else 
                vectorSpace.FrobeniusChangePercent = (double)nudFrobenius.Value / 100;

            Dictionary<Document, double> similarDocuments = null;

            displayItems = new Dictionary<string, Dictionary<Document, double>>();            
            foreach (string document in files)
            {
                similarDocuments = vectorSpace.GetSimilarDocuments(verifiedDocuments[document]);
                displayItems.Add(document, similarDocuments);
            }
        }

        private void bWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
                MessageBox.Show(e.Error.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else
                MessageBox.Show("Verify documents completely!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
            this.Cursor = Cursors.Default;
            EnableControls(true);

            decimal frobenius = Math.Round((decimal)vectorSpace.FrobeniusChangePercent * 100, 2, MidpointRounding.AwayFromZero);
            nudFrobenius.Value = Math.Max(nudValue.Minimum, Math.Min(frobenius, nudValue.Maximum));
            nudValue.Value = vectorSpace.SemanticDimension;

            Display((double)nudCopyDegree.Value / 100);
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            OpenFileDialog txtOpenFileDiagalog = new OpenFileDialog();
            txtOpenFileDiagalog.Filter = "txt files | *.txt";
            txtOpenFileDiagalog.RestoreDirectory = true;
            txtOpenFileDiagalog.Multiselect = true;

            if (txtOpenFileDiagalog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    int ndocs = txtOpenFileDiagalog.FileNames.Length;
                    for (int i = 0; i < ndocs; i++)
                    {
                        string fileName = txtOpenFileDiagalog.SafeFileNames[i];
                        if (!files.Contains(fileName))
                        {
                            string path = txtOpenFileDiagalog.FileNames[i];

                            files.Add(fileName);
                            verifiedDocuments.Add(fileName, path);
                            lbxVerifiedDocuments.Items.Add(path);
                        }                        
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Exception: " + ex.Message, "Exception found", MessageBoxButtons.OK);
                }
            }
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < lbxVerifiedDocuments.SelectedIndices.Count; i++)
            {
                int index = lbxVerifiedDocuments.SelectedIndices[i--];
                verifiedDocuments.Remove(files[index]);
                files.RemoveAt(index);
                lbxVerifiedDocuments.Items.RemoveAt(index);
            }
        }

        private void btnVerify_Click(object sender, EventArgs e)
        {
            if (files.Count == 0)
                MessageBox.Show("Choose file(s) to verify", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
            else
            {
                dgvResults.Rows.Clear();
                this.Cursor = Cursors.WaitCursor;
                EnableControls(false);

                bWorker.RunWorkerAsync();
            }
        }

        private void registerDocumentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmRegistration registerDocument = new frmRegistration();
            registerDocument.ShowDialog();
        }

        private void modelDocumentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmModelCreation documentsModelling = new frmModelCreation();
            documentsModelling.ShowDialog();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmAbout about = new frmAbout();
            about.ShowDialog();
        }

        private void helpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("This function hasn't implemented yet!");
        }

        private void nudThreshold_ValueChanged(object sender, EventArgs e)
        {
            dgvResults.Rows.Clear();
            Display((double)nudCopyDegree.Value / 100);
        }

        private void EnableControls(bool flag)
        {
            foreach (Control ctrl in this.Controls)
            {
                ctrl.Enabled = flag;
            }
        }

        private void Display(double copyDegree)
        {
            if (displayItems != null)
            {
                foreach (KeyValuePair<string, Dictionary<Document, double>> displayItem in displayItems)
                {
                    bool done = false;
                    Dictionary<Document, double> similarDocuments = displayItem.Value;                    
                    foreach (KeyValuePair<Document, double> similarDocument in similarDocuments)
                    {
                        if (similarDocument.Value >= copyDegree)
                        {
                            InsertDataGridViewItem(displayItem.Key, similarDocument.Key, similarDocument.Value);
                            done = true;
                        }
                    }
                    if (done) dgvResults.Rows.Add();
                }
            }
        }

        private void InsertDataGridViewItem(string document, Document registeredDocument, double similarity)
        {            
            string[] row = { document, 
                             registeredDocument.Name, 
                             ConfigReader.BasePath + registeredDocument.Location, 
                             similarity.ToString("P", CultureInfo.InvariantCulture) };
            
            dgvResults.Rows.Add(row);
        }

        private void rbtnFrobenius_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton rbtn = (RadioButton)sender;
            discreteValue = !rbtn.Checked;
            nudFrobenius.Enabled = rbtn.Checked;
            nudValue.Enabled = !rbtn.Checked;
        }

        private void dgvResults_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            string file = string.Empty;
            string strValue = dgvResults.CurrentCell.Value.ToString();

            if (e.ColumnIndex == 0)
            {
                file = verifiedDocuments[strValue];
            }

            if (e.ColumnIndex == 1)
            {
                file = dgvResults.Rows[e.RowIndex].Cells[2].Value.ToString();
            }
            
            if (e.ColumnIndex == 2)
            {
                file = strValue;
            }

            if (file != string.Empty)
            {
                frmTextContent contentViewing = new frmTextContent();
                contentViewing.ShowContent(file);
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            lbxVerifiedDocuments.Items.Clear();
            files.Clear();
            verifiedDocuments.Clear();

            dgvResults.Rows.Clear();
            if (displayItems != null)
                displayItems.Clear();
        }
    }
}
